package com.lyh.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lyh.common.core.domain.AjaxResult;
import com.lyh.common.core.domain.entity.SysUser;
import com.lyh.common.enums.AdvanceSourceEnum;
import com.lyh.common.enums.AdvanceStatusEnum;
import com.lyh.common.enums.AdvanceTypeEnum;
import com.lyh.common.exception.ServiceException;
import com.lyh.common.utils.CommonUtils;
import com.lyh.common.utils.SecurityUtils;
import com.lyh.common.utils.StringUtils;
import com.lyh.system.biz.IPayBiz;
import com.lyh.system.domain.Asset;
import com.lyh.system.domain.UserCashAdvance;
import com.lyh.system.domain.req.*;
import com.lyh.system.domain.resp.UserCashAdvancePageResp;
import com.lyh.system.mapper.AssetMapper;
import com.lyh.system.mapper.SysUserMapper;
import com.lyh.system.mapper.UserCashAdvanceMapper;
import com.lyh.system.service.ICashAdvanceService;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Log4j2
public class CashAdvanceServiceImpl implements ICashAdvanceService {

    @Autowired
    private UserCashAdvanceMapper userCashAdvanceMapper;

    @Autowired
    private IPayBiz payBiz;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private AssetMapper assetMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public List<UserCashAdvancePageResp> selectPageList(UserCashAdvancePageReq req) {

        List<UserCashAdvancePageResp> list = userCashAdvanceMapper.selectAllList(req);
        if (list != null && list.size() > 0) {
            list.stream().forEach(c -> {
                if ("changes".equals(c.getAdvanceSource())) {
                    c.setAdvanceSourceName("零钱");
                } else if ("account_balance".equals(c.getAdvanceSource())) {
                    c.setAdvanceSourceName("余额");
                }
                c.setStatusName(AdvanceStatusEnum.valueOf(c.getStatus()).getMsg());
                c.setAdvanceTypeName(AdvanceTypeEnum.valueOf(c.getAdvanceType()).getMsg());

                //todo lzl 根据用户id获取用户信息，如支付宝账号、真实姓名
                SysUser sysUser = sysUserMapper.selectById(c.getUserId());
                if (sysUser != null){
                    c.setZfbAccount(sysUser.getZfbAccount());
                    c.setUserName(sysUser.getRealName());
                }
            });


        }

        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult audit(MemberPurchasAuditReq req) {
        UserCashAdvance userCashAdvance = userCashAdvanceMapper.selectById(req.getId());
        if (userCashAdvance == null) {
            throw new ServiceException("未找到该提现记录！");
        }
        if (req.getPassFlag() == 1) {

            RLock lock = redissonClient.getLock("cash_" + userCashAdvance.getUserId().toString());
            try {
                if (lock.tryLock(30, 30, TimeUnit.SECONDS)) {
                    //审核通过既支付
                    Long userId = userCashAdvance.getUserId();
                    SysUser sysUser = sysUserMapper.selectById(userId);
                    if (sysUser == null || StringUtils.isEmpty(sysUser.getRealName()) || StringUtils.isEmpty(sysUser.getZfbAccount())) {
                        throw new ServiceException("未填写支付宝账户或支付宝实名");
                    }
                    BigDecimal advanceMoney = userCashAdvance.getAdvanceMoney();
                    Asset asset = assetMapper.selectOne(new LambdaQueryWrapper<Asset>()
                            .eq(Asset::getUserId, sysUser.getUserId()));
                    ZfbCashAdvanceReq cashAdvanceReq = new ZfbCashAdvanceReq();
                    cashAdvanceReq.setAdvanceId(req.getId());
                    cashAdvanceReq.setRealName(sysUser.getRealName());
                    cashAdvanceReq.setZfbAccount(sysUser.getZfbAccount());
                    cashAdvanceReq.setTitle(AdvanceSourceEnum.valueOf(userCashAdvance.getAdvanceSource()).getMsg());
                    boolean result = payBiz.zfbAdvance(cashAdvanceReq);
                    if (result) {
                        if (userCashAdvance.getAdvanceSource().equals(AdvanceSourceEnum.changes.name())) {
                            BigDecimal changes = asset.getChanges();
                            BigDecimal subtract = changes.subtract(advanceMoney);

                            Asset asset1 = new Asset();
                            asset1.setUpdateTime(new Date());
                            asset1.setChanges(subtract);
                            asset1.setId(asset.getId());
                            assetMapper.updateAsset(asset1);
                        } else if (userCashAdvance.getAdvanceSource().equals(AdvanceSourceEnum.account_balance.name())) {
                            BigDecimal accountBalance = asset.getAccountBalance();
                            BigDecimal subtract = accountBalance.subtract(advanceMoney);

                            Asset asset1 = new Asset();
                            asset1.setUpdateTime(new Date());
                            asset1.setAccountBalance(subtract);
                            asset1.setId(asset.getId());
                            assetMapper.updateAsset(asset1);
                        }
                        return AjaxResult.success();

                    }else{
                        //若提现失败，则给出提示
                        return AjaxResult.error("提现失败，请检查支付宝实名和账号是否输入正确！");

                    }
                }
            } catch (Exception e) {
                log.error("提现错误", e);
                throw new ServiceException(e.getMessage());
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }


        } else if (req.getPassFlag() == 0) {
            userCashAdvance.setStatus(AdvanceStatusEnum.fail.name());
            userCashAdvance.setAuditUserId(SecurityUtils.getLoginUser().getUserId());
            userCashAdvance.setAuditTime(new Date());
            int i = userCashAdvanceMapper.updateById(userCashAdvance);
        }
        return AjaxResult.success();


    }

    @Override
    public void batchAudit(MemberPurchasBatchAuditReq req) {
        List<Long> ids = req.getIds();
        for (Long id : ids) {
            MemberPurchasAuditReq auditReq = new MemberPurchasAuditReq();
            auditReq.setId(id);
            auditReq.setPassFlag(req.getPassFlag());
            audit(auditReq);
        }
    }

    @Override
    public int edit(MemberPurchasEditReq req) {
        UserCashAdvance userCashAdvance = userCashAdvanceMapper.selectById(req.getId());
        if (userCashAdvance.getStatus().equals(AdvanceStatusEnum.fail.getCode())) {
            throw new ServiceException("提现失败支持编辑！");
        }
        if (!(req.getStatus().equals(AdvanceStatusEnum.fail.getCode())
                || req.getStatus().equals(AdvanceStatusEnum.wait_audit.getCode()))) {
            throw new ServiceException("状态只可以修改为提现失败，待审核状态！");
        }
        userCashAdvance.setStatus(req.getStatus());
        userCashAdvance.setUpdateBy(SecurityUtils.getLoginUser().getUserId().toString());
        userCashAdvance.setUpdateTime(new Date());
        int i = userCashAdvanceMapper.updateById(userCashAdvance);
        return i;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int apply(AdvanceApplyReq req) {
        if (req.getAdvanceMoney() == null || req.getAdvanceMoney().longValue() % 100 != 0) {
            throw new ServiceException("金额有误，提现金额必须是100的倍数！");
        }
        Asset asset = assetMapper.selectAssetByUserId(SecurityUtils.getLoginUser().getUserId());
        if ("changes".equals(req.getAdvanceSource())) {
            if (asset.getChanges().compareTo(req.getAdvanceMoney()) < 0) {
                throw new ServiceException("您的余额不足！");
            }
            List<UserCashAdvance> userCashAdvances = userCashAdvanceMapper.selectList(new LambdaQueryWrapper<UserCashAdvance>()
                    .eq(UserCashAdvance::getStatus, "wait_audit")
                    .eq(UserCashAdvance::getAdvanceSource, "changes")
                    .eq(UserCashAdvance::getUserId, SecurityUtils.getLoginUser().getUserId()));
            BigDecimal sum = userCashAdvances.stream().map(UserCashAdvance::getAdvanceMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (asset.getChanges().subtract(req.getAdvanceMoney()).subtract(sum).compareTo(new BigDecimal(0)) < 0) {
                throw new ServiceException("您提现的" + sum + "元还在审核中，请勿重复操作！");
            }

        } else if ("account_balance".equals(req.getAdvanceSource())) {
            if (asset.getAccountBalance().compareTo(req.getAdvanceMoney()) < 0) {
                throw new ServiceException("您的余额不足！");
            }
            List<UserCashAdvance> userCashAdvances = userCashAdvanceMapper.selectList(new LambdaQueryWrapper<UserCashAdvance>()
                    .eq(UserCashAdvance::getStatus, "wait_audit")
                    .eq(UserCashAdvance::getAdvanceSource, "account_balance")
                    .eq(UserCashAdvance::getUserId, SecurityUtils.getLoginUser().getUserId()));
            BigDecimal sum = userCashAdvances.stream().map(UserCashAdvance::getAdvanceMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (asset.getAccountBalance().subtract(req.getAdvanceMoney()).subtract(sum).compareTo(new BigDecimal(0)) < 0) {
                throw new ServiceException("您提现的" + sum + "元还在审核中，请勿重复操作！");
            }
        }
        UserCashAdvance userCashAdvance = new UserCashAdvance();
        userCashAdvance.setUserId(SecurityUtils.getLoginUser().getUserId());
        userCashAdvance.setStatus(AdvanceStatusEnum.wait_audit.name());
        userCashAdvance.setAdvanceMoney(req.getAdvanceMoney());
        userCashAdvance.setAdvanceSource(req.getAdvanceSource());
        userCashAdvance.setAdvanceType(req.getAdvanceType());
        userCashAdvance.setOrderNum("Advance" + CommonUtils.getRandom());
        BigDecimal multiply = userCashAdvance.getAdvanceMoney().multiply(new BigDecimal("0.03"));
        userCashAdvance.setServiceFee(multiply);
        return userCashAdvanceMapper.insert(userCashAdvance);

    }
}
